# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: site-packages\jinja2\debug.py
"""
    jinja2.debug
    ~~~~~~~~~~~~

    Implements the debug interface for Jinja.  This module does some pretty
    ugly stuff with the Python traceback system in order to achieve tracebacks
    with correct line numbers, locals and contents.

    :copyright: (c) 2017 by the Jinja Team.
    :license: BSD, see LICENSE for more details.
"""
import sys, traceback
from types import TracebackType, CodeType
from jinja2.utils import missing, internal_code
from jinja2.exceptions import TemplateSyntaxError
from jinja2._compat import iteritems, reraise, PY2

try:
    from __pypy__ import tproxy
except ImportError:
    tproxy = None

try:
    exec("raise TypeError, 'foo'")
except SyntaxError:
    raise_helper = "raise __jinja_exception__[1]"
except TypeError:
    raise_helper = "raise __jinja_exception__[0], __jinja_exception__[1]"


class TracebackFrameProxy(object):
    """Proxies a traceback frame."""

    def __init__(self, tb):
        self.tb = tb
        self._tb_next = None

    @property
    def tb_next(self):
        return self._tb_next

    def set_next(self, next):
        if tb_set_next is not None:
            try:
                tb_set_next(self.tb, next and next.tb or None)
            except Exception:
                pass

            self._tb_next = next

    @property
    def is_jinja_frame(self):
        return "__jinja_template__" in self.tb.tb_frame.f_globals

    def __getattr__(self, name):
        return getattr(self.tb, name)


def make_frame_proxy(frame):
    proxy = TracebackFrameProxy(frame)
    if tproxy is None:
        return proxy
    else:

        def operation_handler(operation, *args, **kwargs):
            if operation in ("__getattribute__", "__getattr__"):
                return getattr(proxy, args[0])
            if operation == "__setattr__":
                proxy.__setattr__(*args, **kwargs)
            else:
                return getattr(proxy, operation)(*args, **kwargs)

        return tproxy(TracebackType, operation_handler)


class ProcessedTraceback(object):
    """Holds a Jinja preprocessed traceback for printing or reraising."""

    def __init__(self, exc_type, exc_value, frames):
        if not frames:
            raise AssertionError("no frames for this traceback?")
        self.exc_type = exc_type
        self.exc_value = exc_value
        self.frames = frames
        prev_tb = None
        for tb in self.frames:
            if prev_tb is not None:
                prev_tb.set_next(tb)
            prev_tb = tb

        prev_tb.set_next(None)

    def render_as_text(self, limit=None):
        """Return a string with the traceback."""
        lines = traceback.format_exception(
            self.exc_type, self.exc_value, self.frames[0], limit=limit
        )
        return ("").join(lines).rstrip()

    def render_as_html(self, full=False):
        """Return a unicode string with the traceback as rendered HTML."""
        from jinja2.debugrenderer import render_traceback

        return "%s\n\n<!--\n%s\n-->" % (
            render_traceback(self, full=full),
            self.render_as_text().decode("utf-8", "replace"),
        )

    @property
    def is_template_syntax_error(self):
        """`True` if this is a template syntax error."""
        return isinstance(self.exc_value, TemplateSyntaxError)

    @property
    def exc_info(self):
        """Exception info tuple with a proxy around the frame objects."""
        return (self.exc_type, self.exc_value, self.frames[0])

    @property
    def standard_exc_info(self):
        """Standard python exc_info for re-raising"""
        tb = self.frames[0]
        if type(tb) is not TracebackType:
            tb = tb.tb
        return (self.exc_type, self.exc_value, tb)


def make_traceback(exc_info, source_hint=None):
    """Creates a processed traceback object from the exc_info."""
    exc_type, exc_value, tb = exc_info
    if isinstance(exc_value, TemplateSyntaxError):
        exc_info = translate_syntax_error(exc_value, source_hint)
        initial_skip = 0
    else:
        initial_skip = 1
    return translate_exception(exc_info, initial_skip)


def translate_syntax_error(error, source=None):
    """Rewrites a syntax error to please traceback systems."""
    error.source = source
    error.translated = True
    exc_info = (error.__class__, error, None)
    filename = error.filename
    if filename is None:
        filename = "<unknown>"
    return fake_exc_info(exc_info, filename, error.lineno)


def translate_exception(exc_info, initial_skip=0):
    """If passed an exc_info it will automatically rewrite the exceptions
    all the way down to the correct line numbers and frames.
    """
    tb = exc_info[2]
    frames = []
    for x in range(initial_skip):
        if tb is not None:
            tb = tb.tb_next

    initial_tb = tb
    while tb is not None:
        if tb.tb_frame.f_code in internal_code:
            tb = tb.tb_next
            continue
            next = tb.tb_next
            template = tb.tb_frame.f_globals.get("__jinja_template__")
            if template is not None:
                lineno = template.get_corresponding_lineno(tb.tb_lineno)
                tb = fake_exc_info(exc_info[:2] + (tb,), template.filename, lineno)[2]
            frames.append(make_frame_proxy(tb))
            tb = next

    if not frames:
        reraise(exc_info[0], exc_info[1], exc_info[2])
    return ProcessedTraceback(exc_info[0], exc_info[1], frames)


def get_jinja_locals(real_locals):
    ctx = real_locals.get("context")
    if ctx:
        locals = ctx.get_all().copy()
    else:
        locals = {}
    local_overrides = {}
    for name, value in iteritems(real_locals):
        if not not name.startswith("l_"):
            if value is missing:
                pass
            else:
                try:
                    _, depth, name = name.split("_", 2)
                    depth = int(depth)
                except ValueError:
                    continue

                cur_depth = local_overrides.get(name, (-1,))[0]
                local_overrides[name] = (cur_depth < depth and depth, value)

    for name, (_, value) in iteritems(local_overrides):
        if value is missing:
            locals.pop(name, None)
        else:
            locals[name] = value

    return locals


def fake_exc_info(exc_info, filename, lineno):
    """Helper for `translate_exception`."""
    exc_type, exc_value, tb = exc_info
    if tb is not None:
        locals = get_jinja_locals(tb.tb_frame.f_locals)
        locals.pop("__jinja_exception__", None)
    else:
        locals = {}
    globals = {
        "__name__": filename,
        "__file__": filename,
        "__jinja_exception__": exc_info[:2],
        "__jinja_template__": None,
    }
    code = compile("\n" * (lineno - 1) + raise_helper, filename, "exec")
    try:
        if tb is None:
            location = "template"
        else:
            function = tb.tb_frame.f_code.co_name
            if function == "root":
                location = "top-level template code"
            else:
                if function.startswith("block_"):
                    location = 'block "%s"' % function[6:]
                else:
                    location = "template"
                if PY2:
                    code = CodeType(
                        0,
                        code.co_nlocals,
                        code.co_stacksize,
                        code.co_flags,
                        code.co_code,
                        code.co_consts,
                        code.co_names,
                        code.co_varnames,
                        filename,
                        location,
                        code.co_firstlineno,
                        code.co_lnotab,
                        (),
                        (),
                    )
                else:
                    code = CodeType(
                        0,
                        code.co_kwonlyargcount,
                        code.co_nlocals,
                        code.co_stacksize,
                        code.co_flags,
                        code.co_code,
                        code.co_consts,
                        code.co_names,
                        code.co_varnames,
                        filename,
                        location,
                        code.co_firstlineno,
                        code.co_lnotab,
                        (),
                        (),
                    )
    except Exception as e:
        pass

    try:
        exec(code, globals, locals)
    except:
        exc_info = sys.exc_info()
        new_tb = exc_info[2].tb_next

    return exc_info[:2] + (new_tb,)


def _init_ugly_crap():
    """This function implements a few ugly things so that we can patch the
    traceback objects.  The function returned allows resetting `tb_next` on
    any python traceback object.  Do not attempt to use this on non cpython
    interpreters
    """
    import ctypes
    from types import TracebackType

    if PY2:
        if hasattr(ctypes.pythonapi, "Py_InitModule4_64"):
            _Py_ssize_t = ctypes.c_int64
        else:
            _Py_ssize_t = ctypes.c_int
    else:
        _Py_ssize_t = ctypes.c_ssize_t

    class _PyObject(ctypes.Structure):
        pass

    _PyObject._fields_ = [
        ("ob_refcnt", _Py_ssize_t),
        ("ob_type", ctypes.POINTER(_PyObject)),
    ]
    if hasattr(sys, "getobjects"):

        class _PyObject(ctypes.Structure):
            pass

        _PyObject._fields_ = [
            ("_ob_next", ctypes.POINTER(_PyObject)),
            ("_ob_prev", ctypes.POINTER(_PyObject)),
            ("ob_refcnt", _Py_ssize_t),
            ("ob_type", ctypes.POINTER(_PyObject)),
        ]

    class _Traceback(_PyObject):
        pass

    _Traceback._fields_ = [
        ("tb_next", ctypes.POINTER(_Traceback)),
        ("tb_frame", ctypes.POINTER(_PyObject)),
        ("tb_lasti", ctypes.c_int),
        ("tb_lineno", ctypes.c_int),
    ]

    def tb_set_next(tb, next):
        """Set the tb_next attribute of a traceback object."""
        if not (
            isinstance(tb, TracebackType)
            and (next is None or isinstance(next, TracebackType))
        ):
            raise TypeError("tb_set_next arguments must be traceback objects")
        obj = _Traceback.from_address(id(tb))
        if tb.tb_next is not None:
            old = _Traceback.from_address(id(tb.tb_next))
            old.ob_refcnt -= 1
        if next is None:
            obj.tb_next = ctypes.POINTER(_Traceback)()
        else:
            next = _Traceback.from_address(id(next))
            next.ob_refcnt += 1
            obj.tb_next = ctypes.pointer(next)

    return tb_set_next


tb_set_next = None
if tproxy is None:
    try:
        tb_set_next = _init_ugly_crap()
    except:
        pass

    del _init_ugly_crap
